//
//  TraitsViewController.swift
//  Example
//
//  Created by T AO on 2022/2/14.
//

import UIKit
import RxSwift

class TraitsViewController: BaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

//        single()
//        asSingle()
        
//        completable()
        
        maybe()
        asMaybe()
    }

}

// MARK: - Single

/// 与数据相关的错误类型
enum DataError: Error {
    case cantParseJSON
}

extension TraitsViewController {
    /// Single 是 Observable 的另外一个版本
    /// 但它不像 Observable 可以发出多个元素，它要么只能发出一个元素，要么产生一个 error 事件
    /// 发出一个元素，或一个 error 事件
    /// 不会共享状态变化
    /// 应用场景：Single 比较常见的例子就是执行 HTTP 请求，然后返回一个应答或错误。不过我们也可以用 Single 来描述任何只有一个元素的序列
    private func single() {
        // 获取第0个频道的歌曲信息
        getPlayList("0")
            .subscribe { event in
                switch event {
                case .success(let json):
                    print("JSON结果：\(json)")
                case .failure(let error):
                    print("发生错误：\(error)")
                }
            }
            .disposed(by: disposeBag)
        
        // 第二种方式
        getPlayList("0")
            .subscribe { json in
                print("JSON结果2：\(json)")
            } onFailure: { error in
                print("发生错误2：\(error)")
            }
            .disposed(by: disposeBag)

    }
    
    /// 获取豆瓣某频道下的歌曲信息
    private func getPlayList(_ channel: String) -> Single<[String: Any]> {
        return Single<[String: Any]>.create { single in
            let url = "https://fm.douban.com/j/mine/playlist?type=n&channel=\(channel)&from=mainsite"
            let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, _, error in
                if let error = error {
                    single(.failure(error))
                    return
                }
                
                guard let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves), let result = json as? [String: Any] else {
                    single(.failure(DataError.cantParseJSON))
                    return
                }
                
                single(.success(result))
            }
            
            task.resume()
            
            return Disposables.create { task.cancel() }
        }
    }
}

// MARK: - asSingle

extension TraitsViewController {
    /// 通过调用 Observable 序列的 .asSingle() 方法，将它转换为 Single
    private func asSingle() {
        Observable.of("1")
            .asSingle()
            .subscribe { print($0) }
            .disposed(by: disposeBag)
    }
}

// MARK: - Completable

/// 与缓存相关的错误类型
enum CacheError: Error {
    case failedCaching
}

extension TraitsViewController {
    /// Completable 是 Observable 的另外一个版本
    /// 不像 Observable 可以发出多个元素，它要么只能产生一个 completed 事件，要么产生一个 error 事件
    ///
    /// 不会发出任何元素
    /// 只会发出一个 completed 事件或者一个 error 事件
    /// 不会共享状态变化
    ///
    /// 使用场景：
    /// Completable 和 Observable<Void> 有点类似。
    /// 适用于那些只关心任务是否完成，而不需要在意任务返回值的情况。比如：在程序退出时将一些数据缓存到本地文件，供下次启动时加载。像这种情况我们只关心缓存是否成功
    private func completable() {
        cacheLocally()
            .subscribe { event in
                switch event {
                case .completed:
                    print("保存成功")
                case .error(let error):
                    print("保存失败：\(error.localizedDescription)")
                }
            }
            .disposed(by: disposeBag)
        
        // 第二种方式
        cacheLocally()
            .subscribe {
                print("保存成功2")
            } onError: { error in
                print("保存失败2：\(error.localizedDescription)")
            }
            .disposed(by: disposeBag)

    }
    
    /// 数据缓存到本地
    private func cacheLocally() -> Completable {
        return Completable.create { completable in
            // 将数据缓存到本地（这里略过具体的业务代码，随机成功或失败）
            let success = (arc4random() % 2 == 0)
            
            guard success else {
                completable(.error(CacheError.failedCaching))
                return Disposables.create {}
            }
            
            completable(.completed)
            return Disposables.create {}
        }
    }
}

// MARK: - Maybe

/// 与缓存相关的错误信息
enum StringError: Error {
    case failedGenerate
}

extension TraitsViewController {
    /// Maybe 同样是 Observable 的另外一个版本
    /// 它介于 Single 和 Completable 之间，它要么只能发出一个元素，要么产生一个 completed 事件，要么产生一个 error 事件
    ///
    /// 应用场景：
    /// Maybe 适合那种可能需要发出一个元素，又可能不需要发出的情况
    private func maybe() {
        generateString()
            .subscribe { event in
                switch event {
                case .success(let element):
                    print("执行完毕，并获得元素：\(element)")
                case .completed:
                    print("执行完毕，且没有任何元素")
                case .error(let error):
                    print("执行失败：\(error.localizedDescription)")
                }
            }
            .disposed(by: disposeBag)
        
        // 第二种方式
        generateString()
            .subscribe { element in
                print("执行完毕，并获得元素2：\(element)")
            } onError: { error in
                print("执行失败2：\(error.localizedDescription)")
            } onCompleted: {
                print("执行完毕，且没有任何元素2")
            }
            .disposed(by: disposeBag)

    }
    
    /// 创建 Maybe 和 创建 Observable 同样非常相似
    private func generateString() -> Maybe<String> {
        return Maybe<String>.create { maybe in
            // 成功并发出一个元素
            maybe(.success("TAO"))
            
            // 成功但不发出任何元素
            maybe(.completed)
            
            // 失败
            maybe(.error(StringError.failedGenerate))
            
            return Disposables.create {}
        }
    }
}

// MARK: - asMaybe

extension TraitsViewController {
    /// 通过调用 Observable 序列的 .asMaybe() 方法，将它转换为 Maybe
    private func asMaybe() {
        Observable.of("1")
            .asMaybe()
            .subscribe { print($0) }
            .disposed(by: disposeBag)
    }
}
